package redisdemo.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class RedisLock implements Lock{
    /**
     * lua脚本
     * 使用lua脚本可以确保整个操作的原子性
     */
    private static String lockStr="if redis.call('get', KEYS[1]) == false " +
            "    then " +
            "        redis.call('set',KEYS[1],ARGV[1],'nx','ex',ARGV[2]) " +
            "        return 1"+
            "    else " +
            "        return 0 " +
            "end";
    private static String unlockStr="if redis.call('get', KEYS[1]) == ARGV[1] " +
            "    then " +
            "        redis.call('del',KEYS[1]) " +
            "        return 1"+
            "    else " +
            "        return 0 " +
            "end";
    private static Long DEFAULT_MINUTES=300L;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Boolean lock(String key, String value) {
        return lock(key,value,DEFAULT_MINUTES.intValue());
    }

    @Override
    public Boolean lock(String key, String value, Integer expired) {
        List<String> keys = new ArrayList<>();
        keys.add(key);
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(lockStr, Long.class);
        Long execute = (Long) redisTemplate.execute(redisScript, new StringRedisSerializer(), new StringRedisSerializer(), keys, value, String.valueOf(expired));
        if(execute==1)
            return true;
        else
            return false;
    }

    @Override
    public Boolean unLock(String key,String value) {
        List<String> keys = new ArrayList<>();
        keys.add(key);
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(unlockStr, Long.class);
        Long execute = (Long) redisTemplate.execute(redisScript,new StringRedisSerializer(),new StringRedisSerializer(),keys,value);
        if(execute==1)
            return true;
        else
            return false;
    }
}
